package com.uuah.server.context.notification;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import com.uuah.server.api.context.notification.linstener.IServerNotificationListener;

/**
 *
 * TODO comment ...
 *
 * <p>
 * update record:updator，update time，update content and version
 * </p>
 *
 * @author <a href="jonny_quan@hotmail.com">jonny</a>
 * @date 2009 2009-3-27 下午01:33:09
 * @version 1.0.0
 */
class EventPolicy {
	private Map eventToSenders = new HashMap();
	private ConcurrentMap knownEventsExact = new ConcurrentHashMap();
	private ConcurrentMap knownEventsSuper = new ConcurrentHashMap();

	EventPolicy(Map interfaceToEvents, Set listenerSubscriptionPairs) {
		for (Iterator pairs = listenerSubscriptionPairs.iterator(); pairs
				.hasNext();) {
			ListenerSubscriptionPair pair = (ListenerSubscriptionPair) pairs
					.next();
			IServerNotificationListener listener = pair.getListener();
			for (Iterator interfaces = interfaceToEvents.keySet().iterator(); interfaces
					.hasNext();) {
				Class iface = (Class) interfaces.next();
				if (iface.isAssignableFrom(listener.getClass())) {
					for (Iterator events = ((Collection) interfaceToEvents
							.get(iface)).iterator(); events.hasNext();) {
						Class event = (Class) events.next();
						knownEventsExact.put(event, Boolean.TRUE);
						knownEventsSuper.put(event, Boolean.TRUE);
						if (!eventToSenders.containsKey(event)) {
							eventToSenders.put(event, new HashSet());
						}
						((Collection) eventToSenders.get(event))
								.add(new EventSender(pair));
					}
				}

			}
		}
	}

	void dispatch(ServerNotification notification) {
		if (null != notification) {
			Class notfnClass = notification.getClass();
			if ((!knownEventsExact.containsKey(notfnClass))
					|| ((Boolean) knownEventsExact.get(notfnClass))
							.booleanValue()) {
				boolean found = false;
				for (Iterator events = eventToSenders.keySet().iterator(); events
						.hasNext();) {
					Class event = (Class) events.next();
					if (event.isAssignableFrom(notfnClass)) {
						found = true;
						for (Iterator senders = ((Collection) eventToSenders
								.get(event)).iterator(); senders.hasNext();) {
							((EventSender) senders.next())
									.dispatch(notification);
						}
					}
				}
				knownEventsExact.put(notfnClass, Boolean.valueOf(found));
			}
		}
	}

	boolean isNotificationEnabled(Class notfnClass) {
		if (!knownEventsSuper.containsKey(notfnClass)) {
			boolean found = false;
			for (Iterator events = knownEventsSuper.keySet().iterator(); events
					.hasNext()
					&& !found;) {
				Class event = (Class) events.next();
				found = ((Boolean) knownEventsSuper.get(event)).booleanValue()
						&& notfnClass.isAssignableFrom(event);
			}
			knownEventsSuper.put(notfnClass, Boolean.valueOf(found));
		}
		if (!knownEventsExact.containsKey(notfnClass)) {
			boolean found = false;
			for (Iterator events = eventToSenders.keySet().iterator(); events
					.hasNext()
					&& !found;) {
				Class event = (Class) events.next();
				found = event.isAssignableFrom(notfnClass);
			}
			knownEventsExact.put(notfnClass, Boolean.valueOf(found));
		}
		return ((Boolean) knownEventsSuper.get(notfnClass)).booleanValue()
				|| ((Boolean) knownEventsExact.get(notfnClass)).booleanValue();
	}

}
